#pragma once
#include <list>
#include "vertex_buffer.h"
#include "index_buffer.h"

namespace krryn{
namespace view{
	class effect;
}
namespace scene{
	class renderable{
	public:
		typedef std::list<krryn::view::effect*> effect_list_t;

		virtual effect_list_t &effects() = 0;
		virtual void draw() = 0;
	};

	template<typename _Type>
	struct aabb{
	public:
		aabb(){
			m_MinX = std::numeric_limits<_Type>::max();
			m_MinY = std::numeric_limits<_Type>::max();
			m_MinZ = std::numeric_limits<_Type>::max();

			m_MaxX = std::numeric_limits<_Type>::min();
			m_MaxY = std::numeric_limits<_Type>::min();
			m_MaxZ = std::numeric_limits<_Type>::min();
		}

		void expand(_Type a_X, _Type a_Y, _Type a_Z){
			m_MaxX = std::max<_Type>(a_X, m_MaxX);
			m_MaxY = std::max<_Type>(a_Y, m_MaxY);
			m_MaxZ = std::max<_Type>(a_Z, m_MaxZ);

			m_MinX = std::min<_Type>(a_X, m_MinX);
			m_MinY = std::min<_Type>(a_Y, m_MinY);
			m_MinZ = std::min<_Type>(a_Z, m_MinZ);
		}

		_Type 
			m_MinX,
			m_MinY,
			m_MinZ,
			m_MaxX,
			m_MaxY,
			m_MaxZ;
	};

	template<typename _RenderTag, typename _VertexType = scene::vertex>
	class mesh : public renderable{
	public:
		typedef mesh* ptr;
		typedef vertex_buffer<_RenderTag, _VertexType> vb;
		typedef index_buffer<_RenderTag> ib;

		typedef typename vertex_buffer<_RenderTag, _VertexType>::ptr vb_ptr;
		typedef typename index_buffer<_RenderTag>::ptr ib_ptr;

		mesh(vb_ptr a_VertexBuffer, ib_ptr a_IndexBuffer) 
			: m_VertexBuffer(a_VertexBuffer), m_IndexBuffer(a_IndexBuffer){}

		virtual void draw(){
			hardware_locker l_VertexRiaa(*m_VertexBuffer, read);
			hardware_locker l_IndexRiaa(*m_IndexBuffer, read);

			//m_VertexBuffer->draw_indexed(*m_IndexBuffer);
			m_VertexBuffer->draw();
		}

		aabb<typename vb::type> get_aabb(){
			return m_AABB;
		}

		void update_aabb(){
			m_VertexBuffer->lock(krryn::scene::read);
			for(vb::iterator i = m_VertexBuffer->begin(); i != m_VertexBuffer->end(); i += m_VertexBuffer->size()){
				m_AABB.expand(i[0], i[1], i[2]);
			}
			m_VertexBuffer->unlock();
		}

		virtual effect_list_t &effects(){return m_Effects;}

		vb_ptr get_vertex_buffer() { return m_VertexBuffer; }
		ib_ptr get_index_buffer() { return m_IndexBuffer; }

	private:
		aabb<typename vb::type> m_AABB;

		effect_list_t m_Effects;
		vb_ptr m_VertexBuffer;
		ib_ptr m_IndexBuffer;
	};
}
}